﻿/*
 * Simple and Quick implemention of ImportedPluginProperty
 * 
 * This class need further re-architect, but the interfaces will be reserved
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CompositionPlugin
{
    public class ImportedPluginProperty
    {
        #region static

        public static ImportedPluginProperty<T> Create<T>(Guid importIdentity, Type owner)
        {
            return Create<T>(importIdentity, new ContractMetadata(typeof(T)), owner);
        }

        public static ImportedPluginProperty<T> Create<T>(Guid importIdentity, ContractMetadata contractMetadata, Type owner)
        {
            if (importIdentity == null)
                throw new ArgumentNullException("importIdentity");
            if (contractMetadata == null)
                throw new ArgumentNullException("contractMetadata");
            if (owner == null)
                throw new ArgumentNullException("owner");
            return new ImportedPluginProperty<T>(BuildImportedPluginContractMetadata(importIdentity, contractMetadata, owner));
        }

        public static ImportedPluginProperty<T, TMetadata> Create<T, TMetadata>(Guid importIdentity, ContractMetadata contractMetadata, Type owner)
        {
            if (importIdentity == null)
                throw new ArgumentNullException("importIdentity");
            if (contractMetadata == null)
                throw new ArgumentNullException("contractMetadata");
            if (owner == null)
                throw new ArgumentNullException("owner");
            return new ImportedPluginProperty<T, TMetadata>(BuildImportedPluginContractMetadata(importIdentity, contractMetadata, owner));
        }

        #endregion

        public ImportedPluginContractMetadata ContractMetadata { get; private set; }

        #region protected

        protected ImportedPluginProperty(ImportedPluginContractMetadata contractMetadata)
        {
            this.ContractMetadata = contractMetadata;
        }

        #endregion

        #region private

        private static ImportedPluginContractMetadata BuildImportedPluginContractMetadata(Guid importIdentity, ContractMetadata contractMetadata, Type owner)
        {
            return new ImportedPluginContractMetadata(
                importIdentity,
                contractMetadata.Name,
                contractMetadata.Type,
                contractMetadata.CreationPolicy,
                contractMetadata.Cardinality,
                owner
                );
        }

        #endregion
    }

    public class ImportedPluginProperty<T> : ImportedPluginProperty
    {
        public T GetValue(object instance)
        {
            return SystemRuntime.Current.ImportedPluginManager.GetPlugin<T>(instance, this.ContractMetadata).Plugin;
        }

        public IEnumerable<T> GetValues(object instance)
        {
            return SystemRuntime.Current.ImportedPluginManager.GetPlugins<T>(instance, this.ContractMetadata).Select(p => p.Plugin);
        }

        internal ImportedPluginProperty(ImportedPluginContractMetadata contractMetadata)
            : base(contractMetadata)
        {
        }
    }

    public class ImportedPluginProperty<T, TMetadata> : ImportedPluginProperty<T>
    {
        public ImportedPlugin<T, TMetadata> GetValueWithMetadata(object instance)
        {
            return SystemRuntime.Current.ImportedPluginManager.GetPlugin<T, TMetadata>(instance, this.ContractMetadata);
        }

        public IEnumerable<ImportedPlugin<T, TMetadata>> GetValuesWithMetadata(object instance)
        {
            return SystemRuntime.Current.ImportedPluginManager.GetPlugins<T, TMetadata>(instance, this.ContractMetadata);
        }

        internal ImportedPluginProperty(ImportedPluginContractMetadata contractMetadata)
            : base(contractMetadata)
        {
        }
    }
}
